package sim.core.handler;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sim.core.annotation.Param;
import sim.core.consts.RequestMethod;
import sim.core.dbrecord.Page;
import sim.core.mvc.Model;
import sim.core.utils.ServletContextUtils;
import sim.core.utils.StringUtils;

/**
 * model执行类
 * 
 * @author Feny
 * @email 1220301855@qq.com
 * @version 1.0
 * @date 2018年7月30日下午1:55:50
 */
public class ControllerHandler {
	// model所在的类
	private Class<?> clazz;
	// 请求url所对应的方法
	private Method method;

	private Object instance;

	/**
	 * 请求类型，GET或POST
	 */
	private RequestMethod[] requestMethod;

	public ControllerHandler(Class<?> clazz, Method method, RequestMethod[] requestMethod) {
		this.clazz = clazz;
		this.method = method;
		this.requestMethod = requestMethod;
		try {
			instance = clazz.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public void invoke() {
		try {
			Object obj = instance;
			// 执行请求地址对应的方法
			Class<?>[] parameterTypes = method.getParameterTypes();
			// 方法带参数
			if (parameterTypes.length > 0) {
				Method m = clazz.getMethod(method.getName(), parameterTypes);
				m.invoke(obj, this.getMethodParameters(method));
			} else {
				try {
					method.invoke(obj);
				} catch (IllegalArgumentException e) {
					throw new IllegalArgumentException(String.format("参数类型不支持：%s.%s()", clazz.getName(), method.getName()));
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 方法参数赋值
	 * 
	 * @author Feny
	 * @date 2019年12月17日下午5:16:44
	 * @param parameterTypes
	 * @return
	 * @throws ParseException
	 */
	private Object[] getMethodParameters(Method method) throws InstantiationException, IllegalAccessException, ParseException {
		List<Object> list = new ArrayList<Object>();
		Parameter[] parameters = method.getParameters();
		for (Parameter parameter : parameters) {
			Class<?> clazz = parameter.getType();
			if (clazz == HttpServletRequest.class) {
				list.add(ServletContextUtils.getRequest());
			} else if (clazz == HttpServletResponse.class) {
				list.add(ServletContextUtils.getResponse());
			} else if (clazz == Model.class || clazz == Page.class) {
				Object obj = clazz.newInstance();
				if (clazz == Page.class) {
					HttpServletRequest request = ServletContextUtils.getRequest();
					String p = request.getParameter("page");
					String ps = request.getParameter("pageSize");
					if (StringUtils.isNotBlank(p)) {
						((Page) obj).setPage(Long.parseLong(p));
					}
					if (StringUtils.isNotBlank(ps)) {
						((Page) obj).setPageSize(Long.parseLong(ps));
					}
				}
				list.add(obj);
			} else if (parameter.isAnnotationPresent(Param.class)) {
				String arg = parameter.getAnnotation(Param.class).value();
				HttpServletRequest request = ServletContextUtils.getRequest();
				list.add(typeConver(clazz, request.getParameter(arg)));
			} else {
				throw new RuntimeException("参数类型不支持");
			}
		}
		return list.toArray();
	}

	/**
	 * 请求参数类型装换
	 * 
	 * @author Feny
	 * @date 2019年12月18日上午10:16:43
	 * @return
	 * @throws ParseException
	 */
	private Object typeConver(Class<?> c, String value) throws ParseException {
		Object res = null;
		if (c == String.class) {
			res = value;
		} else if (c == int.class) {
			res = StringUtils.isBlank(value) ? 0 : Integer.valueOf(value);
		} else if (c == Integer.class) {
			res = Integer.valueOf(value);
		} else if (c == Long.class || c == long.class) {
			res = Long.valueOf(value);
		} else if (c == float.class || c == Float.class) {
			res = Float.valueOf(value);
		} else if (c == Double.class) {
			res = Double.valueOf(value);
		} else if (c == double.class) {
			res = StringUtils.isBlank(value) ? 0 : Double.valueOf(value);
		} else {
			throw new RuntimeException(c + "类型不支持转换");
		}
		return res;

	}

	public Class<?> getClazz() {
		return clazz;
	}

	public void setClazz(Class<?> clazz) {
		this.clazz = clazz;
	}

	public Method getMethod() {
		return method;
	}

	public void setMethod(Method method) {
		this.method = method;
	}

	public RequestMethod[] getRequestMethod() {
		return requestMethod;
	}

	public void setRequestMethod(RequestMethod[] requestMethod) {
		this.requestMethod = requestMethod;
	}

}
